﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Creation;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.Utils;

namespace YJKRevitColumn.ColumnModule
{
	public class ColumnCreator
	{
		public ColumnCreator(UIApplication application, ColumnDatum data)
		{
			this.m_uiApplication = application;
			this.m_uiDocument = application.ActiveUIDocument;
			this.m_application = application.Application;
			this.m_document = this.m_uiDocument.Document;
			this.m_appCreator = application.Application.Create;
			this.m_docCreator = application.ActiveUIDocument.Document.Create;
			this.m_data = data;
		}

		public void SetColumnDatum(ColumnDatum data)
		{
			this.m_data = data;
		}

		public Result GetPointPts(ref List<XYZ> arPts)
		{
			try
			{
				XYZ item = new XYZ(0.0, 0.0, 0.0);
				item = this.m_uiApplication.ActiveUIDocument.Selection.PickPoint("请点取插入点：");
				arPts.Add(item);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result GetAxisPts(ref List<XYZ> arPts)
		{
			try
			{
				AxisFilter axisFilter = new AxisFilter();
				Reference reference = this.m_uiDocument.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, axisFilter, "请选择单根轴线");
				List<Curve> list = new List<Curve>();
				Grid grid = this.m_document.GetElement(reference) as Grid;
				if (grid != null)
				{
					list.Add(grid.Curve);
				}
				MultiSegmentGrid multiSegmentGrid = this.m_document.GetElement(reference) as MultiSegmentGrid;
				if (multiSegmentGrid != null)
				{
					list = AxisAssistFunc.GetLocationCurves(this.m_uiApplication, this.m_document, multiSegmentGrid);
				}
				List<Element> allAxis = AxisAssistFunc.GetAllAxis(this.m_uiApplication);
				IntersectionResultArray intersectionResultArray = null;
				foreach (Curve curve in list)
				{
					foreach (Element element in allAxis)
					{
						Grid grid2 = element as Grid;
						if (grid2 != null)
						{
							Curve curve2 = grid2.Curve;
							curve.Intersect(curve2, out intersectionResultArray);
							if (intersectionResultArray != null && intersectionResultArray.Size == 1)
							{
								XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
								arPts.Add(xyzpoint);
							}
						}
						MultiSegmentGrid multiSegmentGrid2 = element as MultiSegmentGrid;
						if (multiSegmentGrid2 != null)
						{
							new List<Curve>();
							foreach (Curve curve3 in AxisAssistFunc.GetLocationCurves(this.m_uiApplication, this.m_document, multiSegmentGrid2))
							{
								curve.Intersect(curve3, out intersectionResultArray);
								if (intersectionResultArray != null && intersectionResultArray.Size == 1)
								{
									XYZ xyzpoint2 = intersectionResultArray.get_Item(0).XYZPoint;
									arPts.Add(xyzpoint2);
								}
							}
						}
					}
				}
				AssistFunc.CompressArray(arPts);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result GetRectPts(ref List<XYZ> arPts)
		{
			try
			{
				GridFilter gridFilter = new GridFilter();
				this.m_uiDocument.RefreshActiveView();
				IList<Element> list = this.m_uiDocument.Selection.PickElementsByRectangle(gridFilter, "请框选轴线交点");
				IntersectionResultArray intersectionResultArray = null;
				foreach (Element element in list)
				{
					Curve curve = (element as Grid).Curve;
					foreach (Element element2 in list)
					{
						if (!element.Equals(element2))
						{
							Curve curve2 = (element2 as Grid).Curve;
							curve.Intersect(curve2, out intersectionResultArray);
							if (intersectionResultArray != null && intersectionResultArray.Size == 1)
							{
								XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
								arPts.Add(xyzpoint);
							}
						}
					}
				}
				AssistFunc.CompressArray(arPts);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private XYZ SetAnchorPoint(XYZ pt)
		{
			XYZ result = pt;
			if (this.m_data.width > 0.0 && this.m_data.depth > 0.0)
			{
				double num = AssistFunc.mmToFeet(this.m_data.width) / 2.0;
				double num2 = AssistFunc.mmToFeet(this.m_data.depth) / 2.0;
				XYZ xyz = new XYZ(-1.0, 0.0, 0.0);
				XYZ xyz2 = new XYZ(1.0, 0.0, 0.0);
				XYZ xyz3 = new XYZ(0.0, 1.0, 0.0);
				XYZ xyz4 = new XYZ(0.0, -1.0, 0.0);
				switch (this.m_data.anchorPoint)
				{
				case 1:
					result = pt + num * xyz2 + xyz4 * num2;
					break;
				case 2:
					result = pt + num * xyz + xyz4 * num2;
					break;
				case 3:
					result = pt + num * xyz2 + xyz3 * num2;
					break;
				case 4:
					result = pt + num * xyz + xyz3 * num2;
					break;
				}
			}
			return result;
		}

		public bool InsertColumn(XYZ pt, bool isArchColumn)
		{
			XYZ xyz = this.SetAnchorPoint(pt) + XYZ.BasisX * this.m_data.xOffset + XYZ.BasisY * this.m_data.yOffset;
			StructuralType structuralType = 0;
			if (!isArchColumn)
			{
                structuralType = (StructuralType)3;
			}
			UnifiedModified.ActivateFamilySymbol(this.m_data.colSym);
			FamilyInstance familyInstance = this.m_document.Create.NewFamilyInstance(xyz, this.m_data.colSym, this.m_data.level, structuralType);
			Line line = YJKLineEx.YJKGetUnBound(xyz, XYZ.BasisZ);
			double num = AssistFunc.AngleToRadian(this.m_data.angle);
			if (this.m_data.autoRotate)
			{
				num = this.GetAxisXDirection(pt);
			}
			if (this.m_data.autoRotateWall)
			{
				num = this.GetWallXDirection(pt);
			}
			familyInstance.Location.Rotate(line, num);
			this.SetParameter(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, this.m_data.idTopLevel);
			this.SetParameter(familyInstance, BuiltInParameter.FAMILY_LEVEL_PARAM, this.m_data.level.Id);
			this.SetParameter(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM, this.m_data.bottomOffset);
			this.SetParameter(familyInstance, BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM, this.m_data.bottomOffset);
			this.SetParameter(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM, this.m_data.topOffset);
			this.m_document.Regenerate();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_document);
			ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(familyInstance, false);
			filteredElementCollector.WherePasses(elementIntersectsElementFilter);
			filteredElementCollector.Excluding(new List<ElementId>
			{
				familyInstance.Id
			});
			foreach (Element element in filteredElementCollector)
			{
				if (element.Category.Id.IntegerValue == -2000100 || element.Category.Id.IntegerValue == -2001330 || element.Category.Id.IntegerValue == -2000023 || element.Category.Id.IntegerValue == -2000014)
				{
					TaskDialog taskDialog = new TaskDialog("盈建科提示");
					taskDialog.MainInstruction = "X有插入点已有其他不允许相交的设备存在，可能会导致对象重叠，请检查";
					taskDialog.AddCommandLink((TaskDialogCommandLinkId)1001, "继续插入");
					taskDialog.AddCommandLink((TaskDialogCommandLinkId)1002, "取消插入");
                    taskDialog.DefaultButton = (TaskDialogResult)1001;
					taskDialog.TitleAutoPrefix = false;
					TaskDialogResult taskDialogResult = taskDialog.Show();
                    if ((int)taskDialogResult == 1001)
					{
						return true;
					}
                    if ((int)taskDialogResult == 1002)
					{
						return false;
					}
				}
			}
			this.m_document.Regenerate();
			ColumnSplitWallControler columnSplitWallControler = new ColumnSplitWallControler(this.m_uiApplication);
			try
			{
				columnSplitWallControler.ColumnJoinWall(familyInstance, structuralType);
			}
			catch
			{
				return true;
			}
			return true;
		}

		private void SetParameter(FamilyInstance column, BuiltInParameter bPar, ElementId id)
		{
			Parameter parameter = column.get_Parameter(bPar);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(id);
			}
		}

		private void SetParameter(FamilyInstance column, BuiltInParameter bPar, double value)
		{
			Parameter parameter = column.get_Parameter(bPar);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(value);
			}
		}

		private double GetAxisXDirection(XYZ ptPos)
		{
			double num = 0.0;
			List<Element> axisByPoint = AxisAssistFunc.GetAxisByPoint(this.m_uiApplication, ptPos);
			bool flag = false;
			foreach (Element element in axisByPoint)
			{
				Grid grid = element as Grid;
				if (grid != null)
				{
					Line line = grid.Curve as Line;
					if (line == null)
					{
						continue;
					}
					num = (line.GetEndPoint(1) - line.GetEndPoint(0)).AngleOnPlaneTo(XYZ.BasisX, -XYZ.BasisZ);
					if (Math.Abs(num - Math.PI*.5) < 1E-07 || Math.Abs(num - Math.PI) < 1E-07 || Math.Abs(num - 4.71238898038469) < 1E-07 || Math.Abs(num - Math.PI*2) < 1E-07)
					{
						continue;
					}
					flag = true;
				}
				MultiSegmentGrid multiSegmentGrid = element as MultiSegmentGrid;
				if (multiSegmentGrid != null)
				{
					foreach (Curve curve in AxisAssistFunc.GetLocationCurves(this.m_uiApplication, this.m_document, multiSegmentGrid))
					{
						Line line2 = curve as Line;
						if (!(line2 == null))
						{
							num = (line2.GetEndPoint(1) - line2.GetEndPoint(0)).AngleOnPlaneTo(XYZ.BasisX, -XYZ.BasisZ);
							if (Math.Abs(num - Math.PI*.5) >= 1E-07 && Math.Abs(num - Math.PI) >= 1E-07 && Math.Abs(num - 4.71238898038469) >= 1E-07 && Math.Abs(num - Math.PI*2) >= 1E-07)
							{
								flag = true;
							}
						}
					}
				}
				if (flag)
				{
					break;
				}
			}
			return num;
		}

		private double GetWallXDirection(XYZ ptPos)
		{
			double num = 0.0;
			List<Wall> wallsByPoint = ColumnCreator.GetWallsByPoint(this.m_uiApplication, ptPos);
			bool flag = false;
			foreach (Wall wall in wallsByPoint)
			{
				if (wall != null)
				{
					Line line = (wall.Location as LocationCurve).Curve as Line;
					if (line == null)
					{
						continue;
					}
					num = (line.GetEndPoint(1) - line.GetEndPoint(0)).AngleOnPlaneTo(XYZ.BasisX, -XYZ.BasisZ);
					if (Math.Abs(num - Math.PI*.5) < 1E-07 || Math.Abs(num - Math.PI) < 1E-07 || Math.Abs(num - 4.71238898038469) < 1E-07 || Math.Abs(num - Math.PI*2) < 1E-07)
					{
						continue;
					}
					flag = true;
				}
				if (flag)
				{
					break;
				}
			}
			return num;
		}

		public static List<Wall> GetWallsByPoint(UIApplication uiApp, XYZ ptLoc)
		{
			List<Wall> list = new List<Wall>();
            Autodesk.Revit.DB.Document document = uiApp.ActiveUIDocument.ActiveView.Document;
			foreach (Wall wall in ColumnCreator.GetStraightWallList(uiApp))
			{
				double num = 0.0;
				try
				{
					num = document.GetElement(wall.GetTypeId()).GetParameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM).AsDouble();
				}
				catch
				{
					continue;
				}
				Line line = (wall.Location as LocationCurve).Curve as Line;
				XYZ hyendPoint = line.GetEndPoint(0);
				XYZ hyendPoint2 = line.GetEndPoint(1);
				XYZ xyz = Geometry.RotateTo(line.Direction.Normalize(), Math.PI*.5, XYZ.BasisZ);
				XYZ item = hyendPoint + xyz * (num / 2.0);
				XYZ item2 = hyendPoint - xyz * (num / 2.0);
				XYZ item3 = hyendPoint2 - xyz * (num / 2.0);
				XYZ item4 = hyendPoint2 + xyz * (num / 2.0);
				if (Geometry.PointInPloygon(new List<XYZ>
				{
					item,
					item2,
					item3,
					item4
				}, ptLoc, 0.0001, 0.0001) != -1)
				{
					list.Add(wall);
				}
			}
			return list;
		}

		public static List<Wall> GetStraightWallList(UIApplication uiApp)
		{
			List<Wall> list = new List<Wall>();
			foreach (Element element in new FilteredElementCollector(uiApp.ActiveUIDocument.Document).OfClass(typeof(Wall)).ToElements())
			{
				Wall wall = element as Wall;
				if ((wall.Location as LocationCurve).Curve is Line)
				{
					list.Add(wall);
				}
			}
			return list;
		}

		protected UIApplication m_uiApplication;

		protected UIDocument m_uiDocument;

		protected Autodesk.Revit.ApplicationServices.Application m_application;

        protected Autodesk.Revit.DB.Document m_document;

        protected Autodesk.Revit.Creation.Application m_appCreator;

        protected Autodesk.Revit.Creation.Document m_docCreator;

		private const double precision = 1E-07;

		private ColumnDatum m_data;
	}
}
